home *** CD-ROM | disk | FTP | other *** search
- #define LIBQDISPLAY_CORE
- #include "../include/libqdisplay.h"
-
- /*
- * Render a Quake polygon:
- * read it from the db
- * transform it into 3d
- * clip it in 3d
- * compute the 2d texture gradients
- * scan convert
- * pass off the spans
- */
-
- static point_3d defaultPoints[32], *defaultVList[32];
- static fix scan[768][2];
- static struct texture **cachedFaces;
-
- void setup_default_point_list(void)
- {
- int i;
-
- for (i = 32 - 1; i >= 0; --i)
- defaultVList[i] = &defaultPoints[i];
- }
-
- void InitFaceCache(__memBase) {
- if(!(cachedFaces = (struct texture **)kmalloc(bspMem->numfaces * sizeof(struct texture *))))
- Error("failed to allocate face-cache\n");
- }
-
- static void scan_convert(point_3d * a, point_3d * b)
- {
- void *temp;
- int right;
- fix x, dx;
- int y, ey;
-
- if (a->sy == b->sy)
- return;
-
- if (a->sy < b->sy)
- right = 0;
- else {
- temp = a;
- a = b;
- b = temp;
- right = 1;
- }
-
- // compute dxdy
- dx = FLOAT_TO_INT(scalw((b->sx - a->sx), 16) / (b->sy - a->sy)); // * 65536.0
- x = a->sx;
- y = FIX_INT(a->sy);
- ey = FIX_INT(b->sy);
- x += FLOAT_TO_INT(((double)dx * ((y << 16) - a->sy)) * (1 / 65534.0));
-
- while (y < ey) {
- scan[y][right] = x;
- x += dx;
- ++y;
- }
- }
-
- static void draw_poly(int n, point_3d ** vl)
- {
- int i, j, y, ey;
- fix ymin, ymax;
-
- // find max and min y height
- ymin = ymax = vl[0]->sy;
- for (i = 1; i < n; ++i) {
- if (vl[i]->sy < ymin)
- ymin = vl[i]->sy;
- else if (vl[i]->sy > ymax)
- ymax = vl[i]->sy;
- }
-
- // scan out each edge
- j = n - 1;
- for (i = 0; i < n; ++i) {
- scan_convert(vl[i], vl[j]);
- j = i;
- }
-
- y = FIX_INT(ymin);
- ey = FIX_INT(ymax);
-
- // iterate over all spans and draw
- while (y < ey) {
- int sx = FIX_INT(scan[y][0]), ex = FIX_INT(scan[y][1]);
-
- if (sx < ex)
- draw_span((int)y, (int)sx, (int)ex);
- ++y;
- }
- }
-
- static void GetMipMaps(__memBase, struct texture *Text, int TMipMap) {
- struct dmiptexlump_t *mtl = (struct dmiptexlump_t *) bspMem->dtexdata;
- struct mipmap *mip = (struct mipmap *) (bspMem->dtexdata + mtl->dataofs[TMipMap]);
- short int i;
-
- if (mip->name[0] == WARP_MIPMAP) {
- switch(mip->name[1]) {
- case 'w': Text->textureType = WATER_TYPE; break; // *w(ater)...
- case 's': Text->textureType = SLIME_TYPE; break; // *s(lime)...
- case 'l': Text->textureType = LAVA_TYPE; break; // *l(ava)...
- case 't': Text->textureType = TELEPORT_TYPE; break; // *t(eleport)...
- default: Text->textureType = OTHER_TYPE; break; // *...
- }
- Text->mipMaps[MIPMAP_0].rawBody.width = WARP_X;
- Text->mipMaps[MIPMAP_0].rawBody.height = WARP_Y;
- Text->mipMaps[MIPMAP_0].rawBody.size = WARP_X * WARP_Y;
- Text->mipMaps[MIPMAP_0].newBody.width = WARP_X;
- Text->mipMaps[MIPMAP_0].newBody.height = WARP_Y;
- Text->mipMaps[MIPMAP_0].newBody.size = WARP_X * WARP_Y;
- Text->textGradient.u = 0;
- Text->textGradient.v = 0;
- }
- else if (!strncmp(mip->name, SKY_MIPMAP, 3)) {
- Text->textureType = SKY_TYPE;
- Text->mipMaps[MIPMAP_0].rawBody.width = SKY_X;
- Text->mipMaps[MIPMAP_0].rawBody.height = SKY_Y;
- Text->mipMaps[MIPMAP_0].rawBody.size = SKY_X * SKY_Y;
- Text->mipMaps[MIPMAP_0].newBody.width = SKY_X;
- Text->mipMaps[MIPMAP_0].newBody.height = SKY_Y;
- Text->mipMaps[MIPMAP_0].newBody.size = SKY_X * SKY_Y;
- Text->textGradient.u = 0;
- Text->textGradient.v = 0;
- }
- else {
- if(mip->name[0] == ANIM_MIPMAP)
- Text->textureType = ANIM_TYPE;
- else
- Text->textureType = WALL_TYPE;
-
- Text->mipMaps[MIPMAP_0].rawBody.width = LittleLong(mip->width);
- Text->mipMaps[MIPMAP_0].rawBody.height = LittleLong(mip->height);
- Text->mipMaps[MIPMAP_0].rawBody.size = Text->mipMaps[MIPMAP_0].rawBody.width * Text->mipMaps[MIPMAP_0].rawBody.height;
- Text->mipMaps[MIPMAP_0].newBody.width = Text->faceExtent.u10;
- Text->mipMaps[MIPMAP_0].newBody.height = Text->faceExtent.v10;
- Text->mipMaps[MIPMAP_0].newBody.size = Text->mipMaps[MIPMAP_0].newBody.width * Text->mipMaps[MIPMAP_0].newBody.height;
- Text->textGradient.u = Text->faceExtent.u0;
- Text->textGradient.v = Text->faceExtent.v0;
- }
- Text->mipMaps[MIPMAP_0].rawBody.data = (unsigned char *)mip + LittleLong(mip->offsets[MIPMAP_0]);
- Text->mipMaps[MIPMAP_0].step = 16;
- Text->mipMaps[MIPMAP_0].shift = 4;
- Text->mipMaps[MIPMAP_0].row = Text->mipMaps[MIPMAP_0].newBody.width - Text->mipMaps[MIPMAP_0].step;
- if((Text->mipMaps[MIPMAP_0].y = Text->faceExtent.v0 % Text->mipMaps[MIPMAP_0].rawBody.height) < 0)
- Text->mipMaps[MIPMAP_0].y += Text->mipMaps[MIPMAP_0].rawBody.height;
- if((Text->mipMaps[MIPMAP_0].x0 = Text->faceExtent.u0 % Text->mipMaps[MIPMAP_0].rawBody.width) < 0)
- Text->mipMaps[MIPMAP_0].x0 += Text->mipMaps[MIPMAP_0].rawBody.width;
- Text->mipMaps[MIPMAP_0].rescale = scalw((double)(8), -3); // / 8.0;
-
- for(i = MIPMAP_1; i < MIPMAP_MAX; i++) { // an enum cycles, produces no overflow
- Text->mipMaps[i].rawBody.data = (unsigned char *)mip + LittleLong(mip->offsets[i]);
- Text->mipMaps[i].rawBody.width = Text->mipMaps[MIPMAP_0].rawBody.width >> i;
- Text->mipMaps[i].rawBody.height = Text->mipMaps[MIPMAP_0].rawBody.height >> i;
- Text->mipMaps[i].rawBody.size = Text->mipMaps[MIPMAP_0].rawBody.size >> i >> i;
- Text->mipMaps[i].newBody.width = Text->mipMaps[MIPMAP_0].newBody.width >> i;
- Text->mipMaps[i].newBody.height = Text->mipMaps[MIPMAP_0].newBody.height >> i;
- Text->mipMaps[i].newBody.size = Text->mipMaps[MIPMAP_0].newBody.size >> i >> i;
- Text->mipMaps[i].step = 16 >> i;
- Text->mipMaps[i].shift = 4 - i;
- Text->mipMaps[i].row = Text->mipMaps[i].newBody.width - Text->mipMaps[i].step;
- Text->mipMaps[i].rescale = scalw(Text->mipMaps[MIPMAP_0].rescale, -i);
- Text->mipMaps[i].y = Text->mipMaps[MIPMAP_0].y >> i;
- Text->mipMaps[i].x0 = Text->mipMaps[MIPMAP_0].x0 >> i;
- }
-
- if(!(Text->tiled = (unsigned char *)kmalloc((Text->mipMaps[MIPMAP_0].newBody.size + 1) * sizeof(unsigned char))))
- Error("failed to allocate mipmap-body\n");
- Text->texChanged = TRUE; // be very safe
- }
-
- static void GetExtents(__memBase, int face, struct texture *Text, int TInfo) {
- float uv[32][2], *u, *v, umin, umax, vmin, vmax;
- short int i, n = bspMem->dfaces[face].numedges;
- int *se = &bspMem->dsurfedges[bspMem->dfaces[face].firstedge + n];
-
- u = bspMem->texinfo[TInfo].vecs[0];
- v = bspMem->texinfo[TInfo].vecs[1];
-
- for (i = n - 1; i >= 0; --i) {
- int j = *--se;
- float *loc;
-
- if (j < 0)
- loc = bspMem->dvertexes[bspMem->dedges[-j].v[1]].point;
- else
- loc = bspMem->dvertexes[bspMem->dedges[j].v[0]].point;
-
- uv[i][0] = DotProduct(loc, u) + u[3];
- uv[i][1] = DotProduct(loc, v) + v[3];
- }
- umin = umax = uv[0][0];
- vmin = vmax = uv[0][1];
- for (i = n - 1; i >= 0; --i) {
- if (uv[i][0] < umin)
- umin = uv[i][0];
- else if (uv[i][0] > umax)
- umax = uv[i][0];
- if (uv[i][1] < vmin)
- vmin = uv[i][1];
- else if (uv[i][1] > vmax)
- vmax = uv[i][1];
- }
-
- Text->faceExtent.u0 = (int)(umin) & ~15;
- Text->faceExtent.v0 = (int)(vmin) & ~15;
- Text->faceExtent.u1 = (int)(ceil(scalw(umax, -4))) << 4; // / 16
- Text->faceExtent.v1 = (int)(ceil(scalw(vmax, -4))) << 4; // / 16
- Text->faceExtent.u10 = Text->faceExtent.u1 - Text->faceExtent.u0;
- Text->faceExtent.v10 = Text->faceExtent.v1 - Text->faceExtent.v0;
-
- if(bspMem->dfaces[face].lightofs != -1) {
- Text->lightdata = &bspMem->dlightdata[bspMem->dfaces[face].lightofs];
-
- Text->lightmap.width = ((Text->faceExtent.u10) >> 4) + 1;
- Text->lightmap.height = ((Text->faceExtent.v10) >> 4) + 1;
- Text->lightmap.size = Text->lightmap.width * Text->lightmap.height;
- if(!(Text->lightmap.data = (unsigned char *)kmalloc((Text->lightmap.size + 1) * sizeof(int))))
- Error("failed to allocate lightmap for face\n");
-
- for(i = 0; i < MAXLIGHTMAPS; i++) {
- short int lightStyle;
-
- lightStyle = (short int)bspMem->dfaces[face].styles[i];
-
- if(lightStyle == 255)
- break;
- if(lightStyle > 11)
- lightStyle = 0;
-
- Text->lightSString[i] = &lightstyleStrings[lightStyle][0];
- Text->lightSLength[i] = lightstyleLengths[lightStyle];
- }
- }
- else
- Text->lightdata = 0;
-
- Text->texChanged = TRUE; // be very safe
- }
-
- static void GetGradients(__memBase, int face, struct texture *Text, int TInfo) {
- struct dplane_t *plane = Text->textGradient.plane = &bspMem->dplanes[bspMem->dfaces[face].planenum];
- float dot, dot0, dot1;
- vec3_t norm;
- float *vec0 = bspMem->texinfo[TInfo].vecs[0];
- float *vec1 = bspMem->texinfo[TInfo].vecs[1];
-
- CrossProduct(vec0, vec1, norm);
-
- dot = DotProduct(norm, plane->normal);
-
- if((dot0 = -DotProduct(vec0, plane->normal) / dot) != 0) // for setup_uv_vector
- VectorMA(vec0, dot0, norm, Text->textGradient.uv0);
- else
- VectorCopy(vec0, Text->textGradient.uv0);
-
- if((dot1 = -DotProduct(vec1, plane->normal) / dot) != 0) // for setup_uv_vector
- VectorMA(vec1, dot1, norm, Text->textGradient.uv1);
- else
- VectorCopy(vec1, Text->textGradient.uv1);
-
- VectorScale(norm, (plane->dist / dot), Text->textGradient.scaled); // for setup_origin_vector;
-
- Text->textGradient.u -= vec0[3];
- Text->textGradient.v -= vec1[3];
- Text->texChanged = TRUE; // be very safe
- }
-
- static struct texture *cache_face(__memBase, int face) {
- struct texture *Text;
- int TInfo = bspMem->dfaces[face].texinfo;
- int TMipMap = bspMem->texinfo[TInfo].miptex;
-
- if(!(Text = (struct texture *)kmalloc(sizeof(struct texture))))
- Error("failed to allocate texture-cache\n");
-
- GetExtents(bspMem, face, Text, TInfo);
- GetMipMaps(bspMem, Text, TMipMap);
- GetGradients(bspMem, face, Text, TInfo);
- Text->texChanged = TRUE; // be very safe
-
- return Text;
- }
-
- void draw_face(__memBase, int face)
- {
- int n = bspMem->dfaces[face].numedges;
- int se = bspMem->dfaces[face].firstedge;
- int i, edge, codes_or = 0, codes_and = 0xff;
- point_3d **vlist;
-
- for (i = 0; i < n; ++i) {
- edge = bspMem->dsurfedges[se + i];
-
- if (edge < 0)
- transform_point(&defaultPoints[i], &bspMem->dvertexes[bspMem->dedges[-edge].v[1]].point);
- else
- transform_point(&defaultPoints[i], &bspMem->dvertexes[bspMem->dedges[edge].v[0]].point);
-
- codes_or |= defaultPoints[i].ccodes;
- codes_and &= defaultPoints[i].ccodes;
- }
-
- if (codes_and)
- return;
- if (codes_or) // poly crosses frustrum, so clip it
- n = clip_poly(n, defaultVList, codes_or, &vlist);
- else
- vlist = defaultVList;
-
- /*
- * with this texChange-technique it is possible for example
- * to let light render the bsp-tree, then light marks the
- * last processed face as changed and render the tree again
- * and voila, everything is unchanged but the new lightface
- */
- if (n) {
- struct texture *Text;
-
- if(!(Text = cachedFaces[face]))
- Text = cachedFaces[face] = cache_face(bspMem, face);
-
- if((textureMip = compute_mip_level(bspMem, face)) != Text->lastMip) // if the mipmap changes, the tex and it lights changes too
- Text->texChanged = TRUE;
-
- GetTMap(bspMem, Text, textureMip); // GetTMap must have the capability to set texChange
- compute_texture_gradients(bspMem, Text, textureMip);
- draw_poly(n, vlist);
-
- Text->lastMip = textureMip; // set last mip here, perhaps GetTMap should use the old value
-
- /*
- * should we free the whole face if it is an ANIM_MIPMAP?
- * perhaps the sizes etc. changes ...
- */
- }
- }
-